/*
 * Broadcom Home Gateway Reference Design
 * Web Page Configuration Support Routines
 *
 * Copyright 2004, Broadcom Corporation
 * All Rights Reserved.
 * 
 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
 * $Id$
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <unistd.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#include <fcntl.h>
#include <net/if.h>

#include <typedefs.h>
#include <proto/ethernet.h>
#include <bcmnvram.h>
#include <bcmutils.h>
#include <shutils.h>
#include <netconf.h>
#include <nvparse.h>
#include <wlutils.h>

#define wan_prefix(unit, prefix)	snprintf(prefix, sizeof(prefix), "wan%d_", unit)


#define EZC_FLAGS_READ		0x0001
#define EZC_FLAGS_WRITE		0x0002
#define EZC_FLAGS_CRYPT		0x0004

#define EZC_CRYPT_KEY		"620A83A6960E48d1B05D49B0288A2C1F"

#define EZC_SUCCESS	 	0
#define EZC_ERR_NOT_ENABLED 	1
#define EZC_ERR_INVALID_STATE 	2
#define EZC_ERR_INVALID_DATA 	3


typedef u_int64_t u64;
typedef u_int32_t u32;
typedef u_int16_t u16;
typedef u_int8_t u8;

#include <linux/types.h>
#include <linux/ethtool.h>
#include <linux/sockios.h>
#include <net/if_arp.h>

#include "httpd.h"

/* Renew lease */
int
sys_renew(void)
{
	int unit;
	char tmp[100];

	if ((unit = nvram_get_int("wan_unit")) < 0)
		unit = 0;

	snprintf(tmp, sizeof(tmp), "wan_connect,%d", unit);
	nvram_set("rc_service", tmp);
	return kill(1, SIGUSR1);
}

/* Release lease */
int
sys_release(void)
{
	int unit;
	char tmp[100];

	if ((unit = nvram_get_int("wan_unit")) < 0)
		unit = 0;
	
	snprintf(tmp, sizeof(tmp), "wan_disconnect,%d", unit);
	nvram_set("rc_service", tmp);
	return kill(1, SIGUSR1);
}

/* Dump NAT table <tr><td>destination</td><td>MAC</td><td>IP</td><td>expires</td></tr> format */
int
ej_nat_table(int eid, webs_t wp, int argc, char **argv)
{
	int needlen = 0, listlen, i, ret = 0;
	netconf_nat_t *nat_list = NULL;
	char line[256], tstr[32];

	ret += websWrite(wp, "Source          Destination     Proto.  Port range  Redirect to     Local port\n");
	/*                   "255.255.255.255 255.255.255.255 ALL     65535:65535 255.255.255.255 65535:65535" */

	netconf_get_nat(NULL, &needlen);
	if (needlen <= 0)
		return ret;

	nat_list = (netconf_nat_t *) malloc(needlen);
	if (nat_list == NULL)
		return ret;

	memset(nat_list, 0, needlen);
	listlen = needlen;
	if (netconf_get_nat(nat_list, &listlen) == 0 && needlen == listlen)
	{
		listlen = needlen/sizeof(netconf_nat_t);
		for (i = 0; i < listlen; i++)
		{
			//dprintf("%d %d %d\n", nat_list[i].target,
		        //		nat_list[i].match.ipproto,
			//		nat_list[i].match.dst.ipaddr.s_addr);	
			if (nat_list[i].target == NETCONF_DNAT)
			{
				/* Source */
				if (nat_list[i].match.src.ipaddr.s_addr == 0)
					sprintf(line, "%-15s", "ALL");
				else
					sprintf(line, "%-15s", inet_ntoa(nat_list[i].match.src.ipaddr));

				/* Destination */
				if (nat_list[i].match.dst.ipaddr.s_addr == 0)
					sprintf(line, "%s %-15s", line, "ALL");
				else
					sprintf(line, "%s %-15s", line, inet_ntoa(nat_list[i].match.dst.ipaddr));

                                    /* Proto. */
				if (ntohs(nat_list[i].match.dst.ports[0]) == 0)
					sprintf(line, "%s %-7s", line, "ALL");
				else if (nat_list[i].match.ipproto == IPPROTO_TCP)
					sprintf(line, "%s %-7s", line, "TCP");
				else if (nat_list[i].match.ipproto == IPPROTO_UDP)
					sprintf(line, "%s %-7s", line, "UDP");
				else
					sprintf(line, "%s %-7d", line, nat_list[i].match.ipproto);

				/* Port range */
				if (nat_list[i].match.dst.ports[0] == nat_list[i].match.dst.ports[1])
				{
					if (ntohs(nat_list[i].match.dst.ports[0]) == 0)
						sprintf(line, "%s %-11s", line, "ALL");
					else
						sprintf(line, "%s %-11d", line, ntohs(nat_list[i].match.dst.ports[0]));
				} else {
					sprintf(tstr, "%d:%d",
						ntohs(nat_list[i].match.dst.ports[0]),
						ntohs(nat_list[i].match.dst.ports[1]));
					sprintf(line, "%s %-11s", line, tstr);
				}

				/* Redirect to */
				sprintf(line, "%s %-15s", line, inet_ntoa(nat_list[i].ipaddr));

				/* Local port */
				if (nat_list[i].ports[0] == nat_list[i].ports[1])
				{
					if (ntohs(nat_list[i].ports[0]) == 0)
						sprintf(line, "%s %-11s", line, "ALL");
					else
						sprintf(line, "%s %-11d", line, ntohs(nat_list[i].ports[0]));
				} else {
					sprintf(tstr, "%d:%d",
						ntohs(nat_list[i].ports[0]),
						ntohs(nat_list[i].ports[1]));
					sprintf(line, "%s %-11s", line, tstr);
				}

				sprintf(line, "%s\n", line);
				ret += websWrite(wp, line);
			}
	    	}
	}
	free(nat_list);

	return ret;
}

int
ej_route_table(int eid, webs_t wp, int argc, char **argv)
{
	char buff[256];
	int  nl = 0 ;
	struct in_addr dest;
	struct in_addr gw;
	struct in_addr mask;
	int flgs, ref, use, metric;
	int ret = 0;
	char flags[4];
	unsigned long int d,g,m;
	char sdest[16], sgw[16];
	FILE *fp;

        ret += websWrite(wp, "Destination     Gateway         Genmask         Flags Metric Ref    Use Iface\n");

	if (!(fp = fopen("/proc/net/route", "r"))) return 0;

	while (fgets(buff, sizeof(buff), fp) != NULL ) 
	{
		if (nl) 
		{
			int ifl = 0;
			while (buff[ifl]!=' ' && buff[ifl]!='\t' && buff[ifl]!='\0')
				ifl++;
			buff[ifl]=0;    /* interface */
			if (sscanf(buff+ifl+1, "%lx%lx%d%d%d%d%lx",
			   &d, &g, &flgs, &ref, &use, &metric, &m)!=7) {
				//error_msg_and_die( "Unsuported kernel route format\n");
				//continue;
			}

			ifl = 0;        /* parse flags */
			if (flgs&1)
				flags[ifl++]='U';
			if (flgs&2)
				flags[ifl++]='G';
			if (flgs&4)
				flags[ifl++]='H';
			flags[ifl]=0;
			dest.s_addr = d;
			gw.s_addr   = g;
			mask.s_addr = m;
			strcpy(sdest,  (dest.s_addr==0 ? "default" :
					inet_ntoa(dest)));
			strcpy(sgw,    (gw.s_addr==0   ? "*"       :
					inet_ntoa(gw)));

			if (strstr(buff, "br0"))
			{
				ret += websWrite(wp, "%-16s%-16s%-16s%-6s%-6d %-2d %7d LAN %s\n",
				sdest, sgw,
				inet_ntoa(mask),
				flags, metric, ref, use, buff);
			}
			else if(!strstr(buff, "lo"))
			{
				ret += websWrite(wp, "%-16s%-16s%-16s%-6s%-6d %-2d %7d WAN %s\n",
				sdest, sgw,
				inet_ntoa(mask),
				flags, metric, ref, use, buff);
			}
		}
		nl++;
	}
	fclose(fp);

	return 0;
}
